using System;
using System.Threading;
using System.IO;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Blood_Siege
{

    struct m_sTiles
    {
       public int m_nTileID;
       public Rectangle m_rRectangle;

       public void SetRectangle(Rectangle temp)
       {
           m_rRectangle.X = temp.X;
           m_rRectangle.Y = temp.Y;
           m_rRectangle.Width = temp.Width;
           m_rRectangle.Height = temp.Height;
       }
    };

    struct m_sPaths
    {
       public string m_sPathName;
       public List<KeyValuePair<int, int>> m_vPoints;
    };

    struct m_sSpawns
    {
        public int m_nSide;
        public KeyValuePair<int, int> m_vPoints;
    };

    //This screen implements the actual game logic. It is just a
    //placeholder to get the idea across: you'll probably want to
    //put some more interesting gameplay in here!
    class GameplayScreen : GameScreen
    {
        ContentManager content;
        Texture2D Background, Background2, Cursor;

        SpriteFont gameFont;
        BinaryReader BR;
        List<int> m_lMapArray = new List<int>();
        int ImageWidth, ImageHeight, MapWidth, MapHeight, TileSetWidth, TileSetHeight, TileSize,
            OffsetX, OffsetY, PathCount, WaypointCount, SpawnCount, m_nPlots;

        bool m_bMapRendered;


        List<m_sPaths> m_vPaths = new List<m_sPaths>();
        List<m_sSpawns> m_vSpawns = new List<m_sSpawns>();
        List<m_sTiles> m_vTiles = new List<m_sTiles>();

        List<BuildingPlot> m_vLeftPlots = new List<BuildingPlot>();
        List<BuildingPlot> m_vRightPlots = new List<BuildingPlot>();
     
        //Constructor.
        public GameplayScreen()
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);
        }

        //Load graphics content for the game.
        public override void LoadContent()
        {
            if (content == null)
                content = new ContentManager(StateManager.Game.Services, "Content");


            gameFont = content.Load<SpriteFont>("MenuImages/gamefont");
            Background = content.Load<Texture2D>("MapFiles/1");
            Background2 = content.Load<Texture2D>("MapFiles/Terrain_Tiles_resize");
            Cursor = content.Load<Texture2D>("MapFiles/cursor");
            FileStream fs = new FileStream("Content/MapFiles/Water3.tef", FileMode.Open);
            BR = new BinaryReader(fs);
            m_bMapRendered = false;

            // A real game would probably have more content than this sample, so
            // it would take longer to load. We simulate that by delaying for a
            // while, giving you a chance to admire the beautiful loading screen.
            Thread.Sleep(1000);

            // once the load has finished, we use ResetElapsedTime to tell the game's
            // timing mechanism that we have just finished a very long frame, and that
            // it should not try to catch up.
            StateManager.Game.ResetElapsedTime();

            ImageWidth = BR.ReadInt32();
            ImageHeight = BR.ReadInt32();
            MapWidth = BR.ReadInt32();
            MapHeight = BR.ReadInt32();
            TileSetWidth = BR.ReadInt32();
            TileSetHeight = BR.ReadInt32();
            TileSize = BR.ReadInt32();
            OffsetX = BR.ReadInt32();
            OffsetY = BR.ReadInt32();

            m_lMapArray.Clear();
            m_vPaths.Clear();
            m_vSpawns.Clear();
            int TempInt = 0;
            int TempInt2 = 0;
            char TempChar;

            for (int i = 0; i < MapHeight; ++i)
            {
                for (int j = 0; j < MapWidth; ++j)
                {
                    TempInt = BR.ReadInt32();
                    m_lMapArray.Add(TempInt);
                }
            }

            PathCount = BR.ReadInt32();

            for (int i = 0; i < PathCount; ++i)
            {
                m_sPaths tempPaths;
                tempPaths.m_vPoints = new List<KeyValuePair<int, int>>();
                tempPaths.m_sPathName = "";
                int count;
                count = BR.ReadInt32();
                BR.ReadChar().ToString();

                for (int j = 0; j < count; ++j)
                {
                    TempChar = BR.ReadChar();
                    tempPaths.m_sPathName += TempChar.ToString();
                }

                WaypointCount = BR.ReadInt32();

                for (int k = 0; k < WaypointCount; ++k)
                {
                    KeyValuePair<int, int> tempPair;

                    TempInt = BR.ReadInt32();
                    TempInt2 = BR.ReadInt32();
                    tempPair = new KeyValuePair<int, int>(TempInt, TempInt2);
                    tempPaths.m_vPoints.Add(tempPair);
                }
                m_vPaths.Add(tempPaths);
            }

            SpawnCount = BR.ReadInt32();
            m_sSpawns tempSpawn;
            tempSpawn.m_vPoints = new KeyValuePair<int, int>();

            for (int i = 0; i < SpawnCount; ++i)
            {

                KeyValuePair<int, int> tempPair;
                TempInt = BR.ReadInt32();
                TempInt2 = BR.ReadInt32();
                tempPair = new KeyValuePair<int, int>(TempInt, TempInt2);

                tempSpawn.m_vPoints = tempPair;
                tempSpawn.m_nSide = BR.ReadInt32();
                m_vSpawns.Add(tempSpawn);
            }

            BR.Close();

            m_vTiles.Clear();
            for (int i = 0; i < m_lMapArray.Count; ++i)
            {
                m_sTiles tempTile = new m_sTiles();
                tempTile.m_nTileID = m_lMapArray[i];

                for (int j = 0; j < TileSetWidth * TileSetHeight; ++j)
                {
                    if (m_lMapArray[i] == j)
                    {
                        if (j < TileSetWidth)
                        {
                            int X, Y, Width, Height;
                            Rectangle tempRect = new Rectangle(25, 25, 25, 25);
                            X = TileSize * (j % TileSetWidth) + OffsetX;
                            Y = TileSize * (j / TileSetWidth) + OffsetY;
                            Width = TileSize - OffsetX;
                            Height = TileSize - OffsetY;
                            tempTile.m_rRectangle = new Rectangle(X, Y, Width, Height);
                        }
                        else
                        {
                            int X, Y, Width, Height;
                            Rectangle tempRect = new Rectangle(25, 25, 25, 25);
                            X = TileSize * (j % TileSetWidth) + OffsetX;
                            Y = TileSize * (j / TileSetWidth) + OffsetY;
                            Width = TileSize - OffsetX;
                            Height = TileSize - OffsetY;
                            tempTile.m_rRectangle = new Rectangle(X, Y, Width, Height);
                        }
                        m_vTiles.Add(tempTile);
                    }
                }
            }

            m_nPlots = m_vSpawns.Count / 2;


            int leftCounter = 0, rightCounter = 0;

            for (int i = 0; i < m_vSpawns.Count; ++i)
            {
                if (m_vSpawns[i].m_nSide == 1)
                {
                    Rectangle newPlot = new Rectangle();
                    newPlot.X = (m_vSpawns[i].m_vPoints.Key);
                    newPlot.Y = (m_vSpawns[i].m_vPoints.Value);
                    newPlot.Width = TileSize;
                    newPlot.Height = TileSize;

                    BuildingPlot tempTower = new BuildingPlot();
                    tempTower.m_nIndex = leftCounter;
                    tempTower.m_rPlotRectangle = newPlot;
                    m_vLeftPlots.Add(tempTower);
                    leftCounter++;

                }
                else
                {
                    Rectangle newPlot = new Rectangle();
                    newPlot.X = (m_vSpawns[i].m_vPoints.Key);
                    newPlot.Y = (m_vSpawns[i].m_vPoints.Value);
                    newPlot.Width = TileSize;
                    newPlot.Height = TileSize;

                    BuildingPlot tempTower = new BuildingPlot();
                    tempTower.m_nIndex = rightCounter;
                    tempTower.m_rPlotRectangle = newPlot;

                    m_vRightPlots.Add(tempTower);
                    rightCounter++;
                }
            }
        }


        // Unload graphics content used by the game.
        public override void UnloadContent()
        {
            content.Unload();
        }


        //Updates the state of the game. This method checks the GameScreen.IsActive
        //property, so the game will stop updating when the pause menu is active,
        //or if you tab away to a different application.
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            if (IsActive)
            {
                //GO Game Code
            }
        }



        //Lets the game respond to player input. Unlike the Update method,
        //this will only be called when the gameplay screen is active.

        public override void HandleInput(InputState input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = (int)ControllingPlayer.Value;

            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !gamePadState.IsConnected &&
                                       input.GamePadWasConnected[playerIndex];

            if (input.IsPauseGame(ControllingPlayer) || gamePadDisconnected)
            {
                StateManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
            }
            else
            {

            }
        }


        // Draws the gameplay screen.
        public override void Draw(GameTime gameTime)
        {
            // This game has a blue background. Why? Because!
            StateManager.GraphicsDevice.Clear(ClearOptions.Target,
                                               Color.CornflowerBlue, 0, 0);

            MouseState ms = Mouse.GetState();


            // Our player and enemy are both actually just text strings.

            SpriteBatch spriteBatch = StateManager.SpriteBatch;
            Viewport viewport = StateManager.GraphicsDevice.Viewport;
            Rectangle fullscreen = new Rectangle(0, 0, viewport.Width, viewport.Height);
            byte fade = TransitionAlpha;

            spriteBatch.Begin();
            float ScreenScaleWidth, ScreenScaleHeight;
            ScreenScaleWidth = viewport.Width / MapWidth;
            ScreenScaleHeight = viewport.Height / MapHeight;

            float TileSizeWidth = TileSize / ScreenScaleWidth;
            float TileSizeHeight = TileSize / ScreenScaleHeight;

            Vector2 temp = new Vector2(ms.X - Cursor.Width, ms.Y);

            if (m_bMapRendered == false)
            {
                for (int i = 0; i < m_vTiles.Count; ++i)
                {
                    if (i < MapWidth)
                    {
                        Vector2 Position = new Vector2((i * (TileSize - OffsetX)), ((i / MapWidth) * (TileSize - OffsetY)));
                        spriteBatch.Draw(Background2, Position, m_vTiles[i].m_rRectangle, Color.White);
                    }
                    else
                    {
                        Vector2 Position = new Vector2((TileSize - OffsetX) * (i % MapWidth), ((i / MapWidth) * (TileSize - OffsetY)));
                        spriteBatch.Draw(Background2, Position, m_vTiles[i].m_rRectangle, Color.White);


                    }

                    if (m_vTiles.Count == i)
                    {
                        m_bMapRendered = true;
                    }
                }
            }

            spriteBatch.Draw(Cursor, temp, Color.White);


            spriteBatch.End();

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0)
                StateManager.FadeBackBufferToBlack(255 - TransitionAlpha);
        }
    }





    //Helper Methods

}
